#include <unistd.h>

#include "ResourcePool.h"
#include "MutexLocker.h"

ResourcePool::ResourcePool() {
		_last_acquire_resource_index = -1;
		_logger = log4cxx::Logger::getLogger("shadow.sutil.resourcepool");
		pthread_mutex_init(&_mutex, NULL);
}

ResourcePool::~ResourcePool() { 
		pthread_mutex_destroy(&_mutex);
}

int ResourcePool::init(int pool_num, int init_res_flag) {
		_resources.clear();
		for (int i = 0; i < pool_num; i++) {
				Resource res;
				res.set_flag(init_res_flag);
				res.set_index(i);
				_resources.push_back(res);
		}
		return 1;
}

int ResourcePool::get_pool_size() {
		return _resources.size();
}

int ResourcePool::acquire_resource() {
		MutexLocker locker(&_mutex);
//		while (true) {
				locker.lock();
				bool is_begin_index_checked(true);
				int begin_index = _last_acquire_resource_index + 1;
				if (begin_index >= (int)_resources.size()) begin_index = 0;
				for (int i = begin_index;;i++) {
						if (i >= (int)_resources.size()) i = 0;
						if (i == begin_index && !is_begin_index_checked) break;
						is_begin_index_checked = false;
						Resource & res = _resources[i];
						if (res.is_in_use()) continue;
						if (res.acquire() < 0) continue;
						_last_acquire_resource_index = res.get_index();
						locker.unlock();
						return res.get_index();
				}
				locker.unlock();
				LOG4CXX_ERROR(_logger, "can not require resource from resource pool, all resource are in use, "
								"resource pool size:" << _resources.size() << ", last acquire resource index:" << \
								_last_acquire_resource_index);
				return -1;
//				sleep(RESOURCE_POOL_RETRY_INTERVAL);
//		}
//		return 1;
}

int ResourcePool::release_resource(int index) {
		if (index < 0) {
				LOG4CXX_ERROR(_logger, "release resource to resource pool error, invalid index:" << index );
				return -1;
		}
		MutexLocker locker(&_mutex);
		if (index >= (int)_resources.size()) {
				LOG4CXX_ERROR(_logger, "release resource to resource pool error, invalid index:" << index << \
								", resource pool total size:" << _resources.size());
				return -2;
		}
		locker.lock();
		Resource & res = _resources[index];
		res.release();
		locker.unlock();
		return 1;
}

Resource * ResourcePool::get_resource_at(int index) {
		if (index < 0 || index >= (int)_resources.size()) {
				LOG4CXX_ERROR(_logger, "get resource by index error, invalid index:" << index);
				return NULL;
		}
		return &_resources[index];
}
